using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using Clue_Less_Client.localhost;

namespace Clue_Less_Client
{
    /// <summary>
    /// Special class that is used for various rule based validations.
    /// </summary>
    public class Rules
    {
        private Character [] _characters;
        private Board _board;

        public bool CanMove(Player p, Character[] characters)
        {
            try
            {
                if (CanMove(p, _board.GetCell((short)(p.XPosition + 1), p.YPosition), characters))
                    return true;
                if (CanMove(p, _board.GetCell((short)(p.XPosition - 1), p.YPosition), characters))
                    return true;
                if (CanMove(p, _board.GetCell((short)(p.XPosition), (short)(p.YPosition + 1)), characters))
                    return true;
                if (CanMove(p, _board.GetCell((short)(p.XPosition), (short)(p.YPosition - 1)), characters))
                    return true;
                if (CanMove(p, _board.GetCell((short)(p.XPosition + 1), (short)(p.YPosition + 1)), characters))
                    return true;
                if (CanMove(p, _board.GetCell((short)(p.XPosition - 1), (short)(p.YPosition - 1)), characters))
                    return true;
                if (CanMove(p, _board.GetCell((short)(p.XPosition + 1), (short)(p.YPosition - 1)), characters))
                    return true;
                if (CanMove(p, _board.GetCell((short)(p.XPosition - 1), (short)(p.YPosition + 1)), characters))
                    return true;
                return false;
            }
            catch (Exception ex)
            {
                Error.Show("There was an error determining your move.", ex);
                return true;
            }
        }
        /// <summary>
        /// Validates whether player can make a move to the cell
        /// </summary>
        /// <param name="p">Player instance</param>
        /// <param name="location">Boardcell instance of where the mouse is pointing to on the GUI</param>
        /// <returns>True if the location the mouse is pointing to is a valid move location, false otherwise</returns>
        public bool CanMove(Player p, BoardCell location, Character[] characters)
        {
            if (p == null ||
                location == null ||
                characters == null ||
                characters.Length == 0)
                return false;

			BoardCell playerLocation = _board.GetCell(p.XPosition, p.YPosition);
            _characters = characters;
            //Secret passageway moves
			if (playerLocation.IsCorner)
            {
				if (playerLocation.Room == Rooms.Study && location.Room == Rooms.Kitchen)
                    return true;
				if (playerLocation.Room == Rooms.Kitchen && location.Room == Rooms.Study)
                    return true;
				if (playerLocation.Room == Rooms.Lounge && location.Room == Rooms.Conservatory)
                    return true;
				if (playerLocation.Room == Rooms.Conservatory && location.Room == Rooms.Lounge)
                    return true;
            }

            //Checking if south, east, west and north positions are within one moving block of the player
            //Exclusive OR operand, because only one can be true at a time.
            if( ( 
                (p.XPosition+1 == location.XPosition && p.YPosition == location.YPosition) ^
                (p.XPosition == location.XPosition && p.YPosition+1 == location.YPosition) ^
                (p.XPosition-1 == location.XPosition && p.YPosition == location.YPosition) ^
                (p.XPosition == location.XPosition && p.YPosition-1 == location.YPosition)
                ) && !location.IsEmpty)
            {
                if(location.IsRoom)
                    return true;
                if(location.IsCorridor)     //if corridor isn't empty, lose turn?  Need to check for player presence
                {
                    foreach (Character c in _characters)
                    {
                        if((c.XPosition==location.XPosition) && (c.YPosition==location.YPosition))
                            return false;
                    }
                    return true;
                }

            }
           
            return false;
        }

		/// <summary>
		/// Returns true if player can make suggestion
		/// </summary>
		/// <param name="p">Player</param>
		/// <returns>Returns true if player can make suggestion</returns>
        public bool CanSuggest(Player p)
        {
            if(_board.GetCell(p.XPosition, p.YPosition).IsRoom)
                return true;
			else
				return false;
        }
      
        /// <summary>
        /// Returns true is player can disprove
        /// </summary>
        /// <param name="p"></param>
        /// <param name="suggestion"></param>
        /// <returns></returns>
		public bool CanDisprove(Player p, Suggestion suggestion)
        {
            if (suggestion != null &&
                !suggestion.IsDisproved &&
                suggestion.DisproverID == p.PlayerID)
            {
                foreach (Card card in p.Cards)
                {
                    if (suggestion.SuspectCharacter.Name == card.Name ||
                        suggestion.SuspectRoom.Name == card.Name ||
                        suggestion.SuspectWeapon.Name == card.Name)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Returns true is player can disprove with a given card
        /// </summary>
        /// <param name="p"></param>
        /// <param name="suggestion"></param>
        /// <param name="card"></param>
        /// <returns></returns>
        public bool CanDisprove(Player p, Suggestion suggestion, Card card)
        {
            if (card != null && CanDisprove(p, suggestion))
            {
                if (suggestion.SuspectCharacter.Name == card.Name ||
                    suggestion.SuspectRoom.Name == card.Name ||
                    suggestion.SuspectWeapon.Name == card.Name)
                {
                    return true;
                }
            }
            return false;
        }

		/// <summary>
		/// Returns true if player can accuse
		/// </summary>
		/// <param name="p">Player</param>
		/// <returns>True is can accuse</returns>
        public bool CanAccuse(Player p)
        {
            return (p.Status == PlayerStatus.Active);
        }

		/// <summary>
		/// Constructore
		/// </summary>
		/// <param name="envelope">Envelope</param>
		/// <param name="characters">Array of characters</param>
		/// <param name="board">Board</param>
		public Rules(Board board)   //constructor
        {
			_board = board;
        }
    }
}
